package org.jradweb.tools.generator.freemarker;

import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.Column;

import org.apache.maven.plugin.logging.Log;
import org.jradweb.tools.generator.FileAlreadyExistsException;
import org.jradweb.tools.generator.FileOperatorException;
import org.jradweb.tools.generator.FreemarkerTemplateExcepion;
import org.jradweb.tools.generator.freemarker.util.FileGenerator;
import org.jradweb.tools.generator.freemarker.util.Templates;
import org.jradweb.tools.generator.utils.LogImpl;

public class PageGenerator extends ClassGenerator {
	private String pagePath;
	private String classPath;

	public PageGenerator(File projectRootPath, String groupId,
			String artifactId, Log log) {
		super(projectRootPath, groupId, artifactId, log);

		pagePath = projectRootPath.getAbsolutePath()
				+ "/src/main/webapp/WEB-INF/jsp";
		classPath = projectRootPath.getAbsolutePath() + "/target/classes/";
		this.params.put("sy", "${");
	}

	public boolean createIndextPage(String controllerName, String modelName,
			boolean force) throws FileOperatorException,
			FileAlreadyExistsException, FreemarkerTemplateExcepion {
		Value model = new Value(modelName);

		List<Value> columns = this.getProperties(model);

		Value controller = new Value(controllerName);
		params.put("model", model);
		params.put("columns", columns);

		File indexPageFile = new File(this.pagePath + "/"
				+ controller.getLowerCaseFirst() + "/index.jsp");

		try {
			FileGenerator.writeFile(indexPageFile, params,
					Templates.JSP_INDEX_TEMPLATE, force);
		} catch (FileAlreadyExistsException e) {
			log.warn("File " + indexPageFile.getAbsolutePath()
					+ " already exists!");
			return false;
		}

		log.info("File " + indexPageFile.getAbsolutePath()
				+ " created successfully!");

		return true;
	}

	public boolean createCreatePage(String controllerName, String modelName,
			boolean force) throws FileOperatorException,
			FileAlreadyExistsException, FreemarkerTemplateExcepion {
		Value model = new Value(modelName);

		List<Value> columns = this.getProperties(model);

		Value controller = new Value(controllerName);
		params.put("model", model);
		params.put("items", this.toMultiColumn(columns, 2));

		File createPageFile = new File(this.pagePath + "/"
				+ controller.getLowerCaseFirst() + "/create.jsp");

		try {
			FileGenerator.writeFile(createPageFile, params,
					Templates.JSP_CREATE_TEMPLATE, force);
		} catch (FileAlreadyExistsException e) {
			log.warn("File " + createPageFile.getAbsolutePath()
					+ " already exists!");
			return false;
		}

		log.info("File " + createPageFile.getAbsolutePath()
				+ " created successfully!");

		return true;
	}
	
	public boolean createEditPage(String controllerName, String modelName,
			boolean force) throws FileOperatorException,
			FileAlreadyExistsException, FreemarkerTemplateExcepion {
		Value model = new Value(modelName);

		List<Value> columns = this.getProperties(model);

		Value controller = new Value(controllerName);
		params.put("model", model);
		params.put("items", this.toMultiColumn(columns, 2));

		File createPageFile = new File(this.pagePath + "/"
				+ controller.getLowerCaseFirst() + "/edit.jsp");

		try {
			FileGenerator.writeFile(createPageFile, params,
					Templates.JSP_EDIT_TEMPLATE, force);
		} catch (FileAlreadyExistsException e) {
			log.warn("File " + createPageFile.getAbsolutePath()
					+ " already exists!");
			return false;
		}

		log.info("File " + createPageFile.getAbsolutePath()
				+ " created successfully!");

		return true;
	}
	public boolean createShowPage(String controllerName, String modelName,
			boolean force) throws FileOperatorException,
			FileAlreadyExistsException, FreemarkerTemplateExcepion {
		Value model = new Value(modelName);

		List<Value> columns = this.getProperties(model);

		Value controller = new Value(controllerName);
		params.put("model", model);
		params.put("items", this.toMultiColumn(columns, 2));

		File createPageFile = new File(this.pagePath + "/"
				+ controller.getLowerCaseFirst() + "/show.jsp");

		try {
			FileGenerator.writeFile(createPageFile, params,
					Templates.JSP_SHOW_TEMPLATE, force);
		} catch (FileAlreadyExistsException e) {
			log.warn("File " + createPageFile.getAbsolutePath()
					+ " already exists!");
			return false;
		}

		log.info("File " + createPageFile.getAbsolutePath()
				+ " created successfully!");

		return true;
	}

	private List<Value[]> toMultiColumn(List<Value> values, int columnNumber) {
		List<Value[]> mvalues = new ArrayList<Value[]>();

		for (int i = 0; i < values.size(); i++) {
			Value v = values.get(i);
			if (mvalues.isEmpty()) {
				Value[] vs = new Value[columnNumber];
				vs[0] = v;

				mvalues.add(vs);
			} else {
				Value[] mv = mvalues.get(mvalues.size() - 1);
				boolean added = false;
				for (int j = 0; j < columnNumber; j++) {
					if (mv[j] == null) {
						mv[j] = v;
						added = true;
						break;
					}
				}
				if (!added) {
					Value[] vs = new Value[columnNumber];
					vs[0] = v;
					mvalues.add(vs);
				}

			}

		}

		return mvalues;
	}

	private List<Value> getProperties(Value model) {
		URL url = null;
		Class modelClass = null;
		List<Value> columns = new ArrayList<Value>();
		try {
			url = new URL("file:" + classPath);
			
			ClassLoader loader = Thread.currentThread().getContextClassLoader();
			URLClassLoader ucl = new URLClassLoader(new URL[] { url }, loader);
			
			String className = this.groupId + "." + this.artifactId + ".model."
					+ model.getName();
			modelClass = ucl.loadClass(className);
			columns = this.getProperties(modelClass);
		} catch (MalformedURLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return columns;
	}

	private List<Value> getProperties(Class modelClass) {
		List<Value> values = new ArrayList<Value>();
		for (Method method : modelClass.getMethods()) {
			if (method.getAnnotation(Column.class) != null) {
				if (!method.getName().equals("getCreatedAt")
						&& !method.getName().equals("getUpdatedAt")) {
					String name = method.getName().substring(3);
					values.add(new Value(name));
				}
			}
		}
		return values;
	}

	public static void main(String[] args) {

		String model = "Customer";

		try {
			File projectRootPath = new File("D:/workspace2/jradtest");
			PageGenerator cg = new PageGenerator(projectRootPath,
					"org.jradweb", "jradtest",
					new LogImpl(ClassGenerator.class));
			// cg.createModelClass(model);
			// cg.createDao(model);
			// cg.createDaoImpl(model);
			// cg.createService(model, model,true);
			// cg.createAbstractService(model, model,true);
			// cg.createServiceImpl(model, model, true);
			// cg.createController(model, model, model,true);
			//			
			cg.createIndextPage(model, model, true);
			cg.createCreatePage(model, model, true);
			cg.createEditPage(model, model, true);
			cg.createShowPage(model, model, true);
		} catch (FileOperatorException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileAlreadyExistsException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FreemarkerTemplateExcepion e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
